package cn.wenzy.aurora.framework.support.validation;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.*;
import cn.wenzy.aurora.framework.constant.IConstant;
import cn.wenzy.aurora.framework.support.i18n.I18nSupport;
import cn.wenzy.aurora.framework.support.validation.bean.ValidationMessage;
import cn.wenzy.aurora.framework.support.validation.group.Group;
import cn.wenzy.aurora.framework.support.validation.properties.ValidationRule;
import cn.wenzy.aurora.framework.support.validation.properties.ValidationProperties;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validator;
import lombok.AllArgsConstructor;

import java.util.Collection;
import java.util.Date;
import java.util.Set;

@AllArgsConstructor
public class ValidationSupport implements IConstant {


    private I18nSupport i18n;
    private ValidationProperties validationProperties;
    private Validator validator;


    public ValidationMessage validateRule(String ruleCode, String content) {
        ValidationRule rule = validationProperties.getValidationRule(ruleCode);
        return validateRule(rule, content);
    }

    public ValidationMessage validateRule(ValidationRule rule, String content) {
        ValidationMessage validationMessage = ValidationMessage.of(true);
        if (ObjectUtil.isNull(rule)) {
            return validationMessage;
        }
        // 校验长度
        Integer minLength = ArrayUtil.get(rule.getLength(), 0);
        Integer maxLength = ArrayUtil.get(rule.getLength(), 1);
        if (ObjectUtil.isNull(minLength) && minLength > 0 && StrUtil.length(content) < minLength) {
            validationMessage.validate(false, i18n.getMessage(I18N_MESSAGE.VALIDATION.LENGTH, minLength, maxLength));
        }
        if (ObjectUtil.isNull(maxLength) && maxLength > 0 && StrUtil.length(content) > maxLength) {
            validationMessage.validate(false, i18n.getMessage(I18N_MESSAGE.VALIDATION.LENGTH, minLength, maxLength));
        }
        if (StrUtil.isNotBlank(content)){
            // 校验正则
            if (StrUtil.isNotBlank(rule.getRegex()) && !ReUtil.isMatch(rule.getRegex(), content)) {
                validationMessage.validate(false, i18n.getMessage(I18N_MESSAGE.VALIDATION.REGEX, rule.getRegex()));
            }

            // 以字母开头
            if (rule.getStartWithLetter() && CharUtil.isLetter(content.charAt(0))) {
                validationMessage.validate(false, i18n.getMessage(I18N_MESSAGE.VALIDATION.START_WITH_LETTER, rule.getRegex()));
            }

            boolean withUppercaseLetters = false;
            boolean withLowercaseLetters = false;
            boolean withNumbers = false;
            boolean withSpecialCharacters = false;
            boolean noChinese = true;
            for (char c : content.toCharArray()) {
                if (CharUtil.isLetterUpper(c)){
                    withUppercaseLetters = true;
                }
                if (CharUtil.isLetterLower(c)){
                    withLowercaseLetters = true;
                }
                if (CharUtil.isNumber(c)){
                    withNumbers = true;
                }
                if (isChinese(c)){
                    noChinese = false;
                }
                if (StrUtil.contains(rule.getSpecialCharacters().getSpecialCharacters(), c)){
                    withSpecialCharacters = true;
                }
            }
            // 包含大小字母
            if (rule.getWithUppercaseLetters() && !withUppercaseLetters){
                validationMessage.validate(false, i18n.getMessage(I18N_MESSAGE.VALIDATION.WITH_UPPERCASE_LETTERS));
            }
            // 包含小写字母
            if (rule.getWithLowercaseLetters() && !withLowercaseLetters){
                validationMessage.validate(false, i18n.getMessage(I18N_MESSAGE.VALIDATION.WITH_LOWERCASE_LETTERS));
            }
            // 包含数字
            if (rule.getWithNumbers() && !withNumbers){
                validationMessage.validate(false, i18n.getMessage(I18N_MESSAGE.VALIDATION.WITH_NUMBERS));
            }
            // 包含特殊字符
            if (rule.getSpecialCharacters().getEnabled() && !withSpecialCharacters){
                validationMessage.validate(false, i18n.getMessage(I18N_MESSAGE.VALIDATION.WITH_SPECIAL_CHARACTERS));
            }
            // 不含中文
            if (rule.getNoChinese() && !noChinese){
                validationMessage.validate(false, i18n.getMessage(I18N_MESSAGE.VALIDATION.NO_CHINESE));
            }
        }
        if (!validationMessage.isValidate() && StrUtil.isNotBlank(rule.getMessage())) {
            validationMessage = ValidationMessage.of(false, i18n.getMessage(rule.getMessage()));
        }
        return validationMessage;
    }

    public <T> ValidationMessage validate(T t, Class<? extends Group>... group) {
        ValidationMessage validationMessage = ValidationMessage.of(true);
        Set<ConstraintViolation<T>> constraintViolationSet = validator.validate(t, group);
        if (CollUtil.isNotEmpty(constraintViolationSet)) {
            constraintViolationSet.forEach(c -> validationMessage.validate(false, c.getMessage()));
        }
        return validationMessage;
    }


    public <E> ValidationMessage validate(Collection<E> collection, Class<? extends Group>... group) {
        ValidationMessage validationMessage = ValidationMessage.of(true);
        if (CollUtil.isEmpty(collection)) {
            return validationMessage;
        }
        collection.forEach(t -> validationMessage.validate(validate(t, group)));
        return validationMessage;
    }

    public boolean isMatch(String regex, String content) {
       return ReUtil.isMatch(regex, content);
    }

    public boolean validateDate(Date startDate, Date endDate) {
        return validateDateTime(startDate, endDate, true, false, true);
    }

    public boolean validateTime(Date startDate, Date endDate) {
        return validateDateTime(startDate, endDate, true, false, false);
    }

    public boolean validateDateTime(Date startDate, Date endDate, boolean allowNull, boolean allowEq, boolean ignoreTime) {
        if (ObjectUtil.hasNull(startDate, endDate)){
            return allowNull;
        }
        Date start = DateUtil.dateNew(startDate);
        Date end = DateUtil.dateNew(endDate);

        if (ignoreTime){
            start = DateUtil.beginOfDay(start);
            end = DateUtil.beginOfDay(end);
        }
        if (allowEq){
            return start.getTime() <= end.getTime();
        } else {
            return start.getTime() < end.getTime();
        }
    }

    /**
     * 中文字符校验
     * @param c 检验字符
     * @return
     */
    public boolean isChinese(char c) {
        return c >= '\u4e00' && c <= '\u9fa5';
    }
}
